using System;
using System.Collections.Generic;
using System.IO;
using RaisingStudio.SmallBasicCompiler;
using RaisingStudio.SmallProgram.Library;

using RaisingStudio.SmallBasicCompiler.Expressions;
using RaisingStudio.SmallBasicCompiler.Statements;

namespace RaisingStudio.SmallBasicCompiler
{
    public class Parser
    {
        private TextReader _reader;
        private int _currentLine;
        private TokenEnumerator _currentLineEnumerator;
        private bool _rewindRequested;

        private List<Error> _errors;
        public List<Error> Errors
        {
            get
            {
                return this._errors;
            }
            internal set
            {
                this._errors = value;
            }
        }

        private List<Statement> _parseTree;
        public List<Statement> ParseTree
        {
            get
            {
                return this._parseTree;
            }
        }

        private SymbolTable _symbolTable;
        public SymbolTable SymbolTable
        {
            get
            {
                return this._symbolTable;
            }
        }

        public Parser()
            : this(null)
        {
        }

        public Parser(List<Error> errors)
        {
            this._errors = errors;
            if (this._errors == null)
            {
                this._errors = new List<Error>();
            }
            this._symbolTable = new SymbolTable(this._errors);
        }
        public void Parse(TextReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            this._errors.Clear();
            this._symbolTable.Reset();
            this._reader = reader;
            this._parseTree = new List<Statement>();
            this.BuildParseTree();
            foreach (Statement current in this._parseTree)
            {
                current.AddSymbols(this._symbolTable);
            }
        }

        private void BuildParseTree()
        {
            this._currentLine = -1;
            while (true)
            {
                TokenEnumerator tokenEnumerator = this.ReadNextLine();
                if (tokenEnumerator == null)
                {
                    break;
                }
                Statement statementFromTokens = this.GetStatementFromTokens(tokenEnumerator);
                this._parseTree.Add(statementFromTokens);
            }
        }

        internal TokenEnumerator ReadNextLine()
        {
            if (this._rewindRequested)
            {
                this._rewindRequested = false;
                return this._currentLineEnumerator;
            }
            string text = this._reader.ReadLine();
            if (text == null)
            {
                return null;
            }
            this._currentLine++;
            TokenEnumerator tokenList = new LineScanner().GetTokenList(text, this._currentLine);
            this._currentLineEnumerator = tokenList;
            return tokenList;
        }
        internal void RewindLine()
        {
            this._rewindRequested = true;
        }

        internal Statement GetStatementFromTokens(TokenEnumerator tokenEnumerator)
        {
            if (tokenEnumerator.IsEndOfList)
            {
                return new EmptyStatement
                {
                    StartToken = new TokenInfo
                    {
                        Line = tokenEnumerator.LineNumber
                    }
                };
            }
            Statement statement = null;
            TokenInfo current = tokenEnumerator.Current;
            Token token = current.Token;
            if (token != Token.Comment)
            {
                switch (token)
                {
                    case Token.Identifier:
                        {
                            statement = this.ConstructIdentifierStatement(tokenEnumerator);
                            break;
                        }
                    case Token.Else:
                        {
                            break;
                        }
                    case Token.ElseIf:
                        {
                            this.AddError(tokenEnumerator.Current, string.Format(ResourceHelper.GetString("ElseIfUnexpected"), tokenEnumerator.Current.Text));
                            return new IllegalStatement();
                        }
                    default:
                        {
                            switch (token)
                            {
                                case Token.For:
                                    {
                                        statement = this.ConstructForStatement(tokenEnumerator);
                                        break;
                                    }
                                case Token.Goto:
                                    {
                                        statement = this.ConstructGotoStatement(tokenEnumerator);
                                        break;
                                    }
                                case Token.If:
                                    {
                                        statement = this.ConstructIfStatement(tokenEnumerator);
                                        break;
                                    }
                                case Token.Sub:
                                    {
                                        statement = this.ConstructSubStatement(tokenEnumerator);
                                        break;
                                    }
                                case Token.While:
                                    {
                                        statement = this.ConstructWhileStatement(tokenEnumerator);
                                        break;
                                    }
                            }
                            break;
                        }
                }
            }
            else
            {
                statement = new EmptyStatement
                {
                    StartToken = tokenEnumerator.Current
                };
            }
            if (statement == null)
            {
                this.AddError(tokenEnumerator.Current, string.Format(ResourceHelper.GetString("UnexpectedTokenAtLocation"), tokenEnumerator.Current.Text));
                return new IllegalStatement();
            }
            TokenInfo current4 = tokenEnumerator.Current;
            if (current4.Token == Token.Comment)
            {
                statement.EndingComment = tokenEnumerator.Current;
            }
            return statement;
        }

        internal void AddError(string errorDescription)
        {
            this.AddError(this._currentLine, errorDescription);
        }
        internal void AddError(int line, string errorDescription)
        {
            this.AddError(line, 0, errorDescription);
        }
        internal void AddError(int line, int column, string errorDescription)
        {
            this._errors.Add(new Error(line, column, errorDescription));
        }
        internal void AddError(TokenInfo tokenInfo, string errorDescription)
        {
            this._errors.Add(new Error(tokenInfo, errorDescription));
        }

        public static Primitive EvaluateExpression(Expression expression)
        {
            try
            {
                LiteralExpression literalExpression = expression as LiteralExpression;
                if (literalExpression != null)
                {
                    Primitive result = new Primitive(literalExpression.Literal.Text);
                    return result;
                }
                NegativeExpression negativeExpression = expression as NegativeExpression;
                if (negativeExpression != null)
                {
                    Primitive result = -Parser.EvaluateExpression(negativeExpression.Expression);
                    return result;
                }
                BinaryExpression binaryExpression = expression as BinaryExpression;
                if (binaryExpression != null)
                {
                    Primitive primitive = Parser.EvaluateExpression(binaryExpression.LeftHandSide);
                    Primitive primitive2 = Parser.EvaluateExpression(binaryExpression.RightHandSide);
                    switch (binaryExpression.Operator.Token)
                    {
                        case Token.And:
                            {
                                Primitive result = Primitive.op_And(primitive, primitive2);
                                return result;
                            }
                        case Token.Equals:
                            {
                                Primitive result = primitive.EqualTo(primitive2);
                                return result;
                            }
                        case Token.Or:
                            {
                                Primitive result = Primitive.op_Or(primitive, primitive2);
                                return result;
                            }
                        case Token.Addition:
                            {
                                Primitive result = primitive + primitive2;
                                return result;
                            }
                        case Token.Subtraction:
                            {
                                Primitive result = primitive - primitive2;
                                return result;
                            }
                        case Token.Division:
                            {
                                Primitive result = primitive / primitive2;
                                return result;
                            }
                        case Token.Multiplication:
                            {
                                Primitive result = primitive * primitive2;
                                return result;
                            }
                        case Token.LessThan:
                            {
                                Primitive result = primitive.LessThan(primitive2);
                                return result;
                            }
                        case Token.LessThanEqualTo:
                            {
                                Primitive result = primitive.LessThanOrEqualTo(primitive2);
                                return result;
                            }
                        case Token.GreaterThan:
                            {
                                Primitive result = primitive.GreaterThan(primitive2);
                                return result;
                            }
                        case Token.GreaterThanEqualTo:
                            {
                                Primitive result = primitive.GreaterThanOrEqualTo(primitive2);
                                return result;
                            }
                        case Token.NotEqualTo:
                            {
                                Primitive result = primitive.NotEqualTo(primitive2);
                                return result;
                            }
                    }
                }
            }
            catch
            {
            }
            return 0;
        }

        internal bool EatToken(TokenEnumerator tokenEnumerator, Token expectedToken, out TokenInfo tokenInfo)
        {
            if (!tokenEnumerator.IsEndOfList)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == expectedToken)
                {
                    tokenInfo = tokenEnumerator.Current;
                    tokenEnumerator.MoveNext();
                    return true;
                }
            }
            tokenInfo = TokenInfo.Illegal;
            this._errors.Add(new Error(tokenEnumerator.Current, string.Format(ResourceHelper.GetString("TokenExpected"), expectedToken)));
            return false;
        }
        internal bool EatToken(TokenEnumerator tokenEnumerator, Token expectedToken)
        {
            TokenInfo tokenInfo;
            return this.EatToken(tokenEnumerator, expectedToken, out tokenInfo);
        }
        internal bool EatOptionalToken(TokenEnumerator tokenEnumerator, Token optionalToken, out TokenInfo tokenInfo)
        {
            if (!tokenEnumerator.IsEndOfList)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == optionalToken)
                {
                    tokenInfo = tokenEnumerator.Current;
                    tokenEnumerator.MoveNext();
                    return true;
                }
            }
            tokenInfo = TokenInfo.Illegal;
            return false;
        }
        internal bool EatOptionalToken(TokenEnumerator tokenEnumerator, Token optionalToken)
        {
            TokenInfo tokenInfo;
            return this.EatOptionalToken(tokenEnumerator, optionalToken, out tokenInfo);
        }
        internal bool EatSimpleIdentifier(TokenEnumerator tokenEnumerator, out TokenInfo variable)
        {
            if (!tokenEnumerator.IsEndOfList)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.Identifier)
                {
                    variable = tokenEnumerator.Current;
                    tokenEnumerator.MoveNext();
                    return true;
                }
            }
            variable = TokenInfo.Illegal;
            this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("IdentifierExpected")));
            return false;
        }
        internal bool EatExpression(TokenEnumerator tokenEnumerator, out Expression expression)
        {
            expression = this.BuildArithmeticExpression(tokenEnumerator);
            if (expression != null)
            {
                return true;
            }
            this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("ExpressionExpected")));
            return false;
        }
        internal bool EatLogicalExpression(TokenEnumerator tokenEnumerator, out Expression expression)
        {
            expression = this.BuildLogicalExpression(tokenEnumerator);
            if (expression != null)
            {
                return true;
            }
            this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("ConditionExpected")));
            return false;
        }

        internal bool ExpectEndOfLine(TokenEnumerator tokenEnumerator)
        {
            if (tokenEnumerator.IsEndOfNonCommentList)
            {
                return true;
            }
            this._errors.Add(new Error(tokenEnumerator.Current, string.Format(ResourceHelper.GetString("UnexpectedTokenFound"), tokenEnumerator.Current.Text)));
            return false;
        }

        public Expression BuildArithmeticExpression(TokenEnumerator tokenEnumerator)
        {
            return this.BuildExpression(tokenEnumerator, false);
        }
        public Expression BuildLogicalExpression(TokenEnumerator tokenEnumerator)
        {
            return this.BuildExpression(tokenEnumerator, true);
        }

        private Expression BuildExpression(TokenEnumerator tokenEnumerator, bool includeLogical)
        {
            if (!tokenEnumerator.IsEndOfList)
            {
                TokenInfo current = tokenEnumerator.Current;
                Expression currentExpression = this.BuildTerm(tokenEnumerator, includeLogical);
                if (currentExpression != null)
                {
                    while (this.IsValidOperator(tokenEnumerator.Current.Token, includeLogical))
                    {
                        TokenInfo operatorToken = tokenEnumerator.Current;
                        tokenEnumerator.MoveNext();
                        Expression term = this.BuildTerm(tokenEnumerator, includeLogical);
                        if (term == null)
                        {
                            return null;
                        }
                        currentExpression = this.MergeExpression(currentExpression, term, operatorToken);
                    }
                    currentExpression.StartToken = current;
                    currentExpression.EndToken = tokenEnumerator.Current;
                    return currentExpression;
                }
            }
            return null;
        }

        private Expression BuildTerm(TokenEnumerator tokenEnumerator, bool includeLogical)
        {
            TokenInfo current = tokenEnumerator.Current;
            if (tokenEnumerator.IsEndOfList || (tokenEnumerator.Current.Token == Token.Illegal))
            {
                return null;
            }
            Expression expression = null;
            if ((tokenEnumerator.Current.Token == Token.StringLiteral) || (tokenEnumerator.Current.Token == Token.NumericLiteral))
            {
                LiteralExpression expression2 = new LiteralExpression();
                expression2.Literal = tokenEnumerator.Current;
                expression = expression2;
                expression.Precedence = 9;
                tokenEnumerator.MoveNext();
            }
            else if (tokenEnumerator.Current.Token == Token.LeftParens)
            {
                tokenEnumerator.MoveNext();
                expression = this.BuildExpression(tokenEnumerator, includeLogical);
                if (expression == null)
                {
                    return null;
                }
                expression.Precedence = 9;
                if (!this.EatToken(tokenEnumerator, Token.RightParens))
                {
                    return null;
                }
            }
            else if (tokenEnumerator.Current.Token == Token.Identifier)
            {
                expression = this.BuildIdentifierTerm(tokenEnumerator);
                if (expression == null)
                {
                    return null;
                }
            }
            else
            {
                if (tokenEnumerator.Current.Token != Token.Subtraction)
                {
                    return null;
                }
                tokenEnumerator.MoveNext();
                Expression expression3 = this.BuildTerm(tokenEnumerator, includeLogical);
                if (expression3 == null)
                {
                    return null;
                }
                NegativeExpression expression4 = new NegativeExpression();
                expression4.Negation = tokenEnumerator.Current;
                expression4.Expression = expression3;
                expression4.Precedence = 9;
                expression = expression4;
            }
            expression.StartToken = current;
            expression.EndToken = tokenEnumerator.Current;
            return expression;
        }
        
        private Expression MergeExpression(Expression currentExpression, Expression term, TokenInfo operatorToken)
        {
            int operatorPriority = Parser.GetOperatorPriority(operatorToken.Token);
            BinaryExpression binaryExpression = currentExpression as BinaryExpression;
            if (operatorPriority <= currentExpression.Precedence)
            {
                return new BinaryExpression
                {
                    Operator = operatorToken,
                    Precedence = operatorPriority,
                    StartToken = currentExpression.StartToken,
                    EndToken = term.EndToken,
                    LeftHandSide = currentExpression,
                    RightHandSide = term
                };
            }
            if (binaryExpression != null)
            {
                Expression rightHandSide = binaryExpression.RightHandSide;
                Expression rightHandSide2 = null;
                if (rightHandSide is BinaryExpression)
                {
                    rightHandSide2 = this.MergeExpression(rightHandSide, term, operatorToken);
                }
                else
                {
                    rightHandSide2 = new BinaryExpression
                    {
                        Operator = operatorToken,
                        Precedence = operatorPriority,
                        StartToken = rightHandSide.StartToken,
                        EndToken = term.EndToken,
                        LeftHandSide = rightHandSide,
                        RightHandSide = term
                    };
                }
                binaryExpression.RightHandSide = rightHandSide2;
                binaryExpression.EndToken = term.EndToken;
                return binaryExpression;
            }
            return null;
        }
        private Expression BuildIdentifierTerm(TokenEnumerator tokenEnumerator)
        {
            TokenInfo current = tokenEnumerator.Current;
            tokenEnumerator.MoveNext();
            TokenInfo current2 = tokenEnumerator.Current;
            if (current2.Token == Token.Dot)
            {
                tokenEnumerator.MoveNext();
                TokenInfo tokenInfo;
                if (!this.EatSimpleIdentifier(tokenEnumerator, out tokenInfo))
                {
                    return null;
                }
                if (this.EatOptionalToken(tokenEnumerator, Token.LeftParens))
                {
                    MethodCallExpression methodCallExpression = new MethodCallExpression
                    {
                        StartToken = current,
                        Precedence = 9,
                        TypeName = current,
                        MethodName = tokenInfo
                    };
                    while (true)
                    {
                        TokenInfo current3 = tokenEnumerator.Current;
                        if (current3.Token == Token.RightParens)
                        {
                            goto IL_F3;
                        }
                        Expression expression = this.BuildArithmeticExpression(tokenEnumerator);
                        if (expression == null)
                        {
                            break;
                        }
                        methodCallExpression.Arguments.Add(expression);
                        this.EatOptionalToken(tokenEnumerator, Token.Comma);
                        if (tokenEnumerator.IsEndOfNonCommentList)
                        {
                            goto Block_5;
                        }
                    }
                    this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("ExpressionExpected")));
                    goto IL_F3;
                Block_5:
                    this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("UnexpectedMethodCallEOL")));
                IL_F3:
                    methodCallExpression.EndToken = tokenEnumerator.Current;
                    tokenEnumerator.MoveNext();
                    return methodCallExpression;
                }
                return new PropertyExpression
                {
                    StartToken = current,
                    EndToken = tokenInfo,
                    Precedence = 9,
                    TypeName = current,
                    PropertyName = tokenInfo
                };
            }
            else
            {
                TokenInfo current4 = tokenEnumerator.Current;
                if (current4.Token == Token.LeftBracket)
                {
                    Expression leftHand = new IdentifierExpression
                    {
                        StartToken = current,
                        Identifier = current,
                        EndToken = current,
                        Precedence = 9
                    };
                    Expression expression2;
                    while (true)
                    {
                        this.EatToken(tokenEnumerator, Token.LeftBracket);
                        expression2 = this.BuildArithmeticExpression(tokenEnumerator);
                        if (expression2 == null)
                        {
                            break;
                        }
                        this.EatToken(tokenEnumerator, Token.RightBracket);
                        TokenInfo current5 = tokenEnumerator.Current;
                        if (current5.Token != Token.LeftBracket)
                        {
                            goto IL_213;
                        }
                        leftHand = new ArrayExpression
                        {
                            StartToken = current,
                            EndToken = tokenEnumerator.Current,
                            Precedence = 9,
                            LeftHand = leftHand,
                            Indexer = expression2
                        };
                    }
                    this._errors.Add(new Error(tokenEnumerator.Current, ResourceHelper.GetString("ExpressionExpected")));
                IL_213:
                    return new ArrayExpression
                    {
                        StartToken = current,
                        EndToken = tokenEnumerator.Current,
                        Precedence = 9,
                        LeftHand = leftHand,
                        Indexer = expression2
                    };
                }
                return new IdentifierExpression
                {
                    StartToken = current,
                    EndToken = current,
                    Precedence = 9,
                    Identifier = current
                };
            }
        }

        private bool IsValidOperator(Token token, bool includeLogical)
        {
            int operatorPriority = Parser.GetOperatorPriority(token);
            if (includeLogical)
            {
                return operatorPriority > 0;
            }
            return operatorPriority >= 7;
        }
        internal static int GetOperatorPriority(Token token)
        {
            switch (token)
            {
                case Token.And:
                    {
                        return 4;
                    }
                case Token.Equals:
                case Token.NotEqualTo:
                    {
                        return 5;
                    }
                case Token.Or:
                    {
                        return 3;
                    }
                case Token.Addition:
                case Token.Subtraction:
                    {
                        return 7;
                    }
                case Token.Division:
                case Token.Multiplication:
                    {
                        return 8;
                    }
                case Token.LessThan:
                case Token.LessThanEqualTo:
                case Token.GreaterThan:
                case Token.GreaterThanEqualTo:
                    {
                        return 6;
                    }
            }
            return 0;
        }

        private WhileStatement ConstructWhileStatement(TokenEnumerator tokenEnumerator)
        {
            WhileStatement whileStatement = new WhileStatement
            {
                StartToken = tokenEnumerator.Current,
                WhileToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatLogicalExpression(tokenEnumerator, out whileStatement.Condition))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            tokenEnumerator = this.ReadNextLine();
            bool flag = false;
            while (tokenEnumerator != null)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.EndWhile)
                {
                    whileStatement.EndWhileToken = tokenEnumerator.Current;
                    flag = true;
                    break;
                }
                TokenInfo current2 = tokenEnumerator.Current;
                if (current2.Token == Token.Sub)
                {
                    break;
                }
                TokenInfo current3 = tokenEnumerator.Current;
                if (current3.Token == Token.EndSub)
                {
                    break;
                }
                whileStatement.WhileBody.Add(this.GetStatementFromTokens(tokenEnumerator));
                tokenEnumerator = this.ReadNextLine();
            }
            if (flag)
            {
                tokenEnumerator.MoveNext();
                this.ExpectEndOfLine(tokenEnumerator);
            }
            else
            {
                this.AddError(ResourceHelper.GetString("EndWhileExpected"));
            }
            return whileStatement;
        }
        private ForStatement ConstructForStatement(TokenEnumerator tokenEnumerator)
        {
            ForStatement forStatement = new ForStatement
            {
                StartToken = tokenEnumerator.Current,
                ForToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatSimpleIdentifier(tokenEnumerator, out forStatement.Iterator) && this.EatToken(tokenEnumerator, Token.Equals) && this.EatExpression(tokenEnumerator, out forStatement.InitialValue) && this.EatToken(tokenEnumerator, Token.To, out forStatement.ToToken) && this.EatExpression(tokenEnumerator, out forStatement.FinalValue) && (!this.EatOptionalToken(tokenEnumerator, Token.Step, out forStatement.StepToken) || this.EatExpression(tokenEnumerator, out forStatement.StepValue)))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            tokenEnumerator = this.ReadNextLine();
            bool flag = false;
            while (tokenEnumerator != null)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.EndFor)
                {
                    forStatement.EndForToken = tokenEnumerator.Current;
                    flag = true;
                    break;
                }
                TokenInfo current2 = tokenEnumerator.Current;
                if (current2.Token == Token.Sub)
                {
                    break;
                }
                TokenInfo current3 = tokenEnumerator.Current;
                if (current3.Token == Token.EndSub)
                {
                    break;
                }
                forStatement.ForBody.Add(this.GetStatementFromTokens(tokenEnumerator));
                tokenEnumerator = this.ReadNextLine();
            }
            if (flag)
            {
                tokenEnumerator.MoveNext();
                this.ExpectEndOfLine(tokenEnumerator);
            }
            else
            {
                this.AddError(ResourceHelper.GetString("EndForExpected"));
            }
            return forStatement;
        }
        private IfStatement ConstructIfStatement(TokenEnumerator tokenEnumerator)
        {
            IfStatement ifStatement = new IfStatement
            {
                StartToken = tokenEnumerator.Current,
                IfToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatLogicalExpression(tokenEnumerator, out ifStatement.Condition) && this.EatToken(tokenEnumerator, Token.Then, out ifStatement.ThenToken))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            tokenEnumerator = this.ReadNextLine();
            bool flag = false;
            bool flag2 = false;
            bool flag3 = false;
            while (tokenEnumerator != null)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.EndIf)
                {
                    ifStatement.EndIfToken = tokenEnumerator.Current;
                    flag = true;
                    break;
                }
                TokenInfo current2 = tokenEnumerator.Current;
                if (current2.Token == Token.Else)
                {
                    ifStatement.ElseToken = tokenEnumerator.Current;
                    flag3 = true;
                    break;
                }
                TokenInfo current3 = tokenEnumerator.Current;
                if (current3.Token == Token.ElseIf)
                {
                    flag2 = true;
                    break;
                }
                TokenInfo current4 = tokenEnumerator.Current;
                if (current4.Token == Token.Sub)
                {
                    break;
                }
                TokenInfo current5 = tokenEnumerator.Current;
                if (current5.Token == Token.EndSub)
                {
                    break;
                }
                ifStatement.ThenStatements.Add(this.GetStatementFromTokens(tokenEnumerator));
                tokenEnumerator = this.ReadNextLine();
            }
            if (flag2)
            {
                while (tokenEnumerator != null)
                {
                    TokenInfo current6 = tokenEnumerator.Current;
                    if (current6.Token == Token.EndIf)
                    {
                        ifStatement.EndIfToken = tokenEnumerator.Current;
                        flag = true;
                        break;
                    }
                    TokenInfo current7 = tokenEnumerator.Current;
                    if (current7.Token == Token.Else)
                    {
                        ifStatement.ElseToken = tokenEnumerator.Current;
                        flag3 = true;
                        break;
                    }
                    TokenInfo current8 = tokenEnumerator.Current;
                    if (current8.Token == Token.Sub)
                    {
                        break;
                    }
                    TokenInfo current9 = tokenEnumerator.Current;
                    if (current9.Token == Token.EndSub)
                    {
                        break;
                    }
                    TokenInfo current10 = tokenEnumerator.Current;
                    if (current10.Token != Token.ElseIf)
                    {
                        break;
                    }
                    ifStatement.ElseIfStatements.Add(this.ConstructElseIfStatement(ref tokenEnumerator));
                }
            }
            if (flag3)
            {
                tokenEnumerator.MoveNext();
                this.ExpectEndOfLine(tokenEnumerator);
                for (tokenEnumerator = this.ReadNextLine(); tokenEnumerator != null; tokenEnumerator = this.ReadNextLine())
                {
                    TokenInfo current11 = tokenEnumerator.Current;
                    if (current11.Token == Token.EndIf)
                    {
                        ifStatement.EndIfToken = tokenEnumerator.Current;
                        flag = true;
                        break;
                    }
                    TokenInfo current12 = tokenEnumerator.Current;
                    if (current12.Token == Token.Sub)
                    {
                        break;
                    }
                    TokenInfo current13 = tokenEnumerator.Current;
                    if (current13.Token == Token.EndSub)
                    {
                        break;
                    }
                    TokenInfo current14 = tokenEnumerator.Current;
                    if (current14.Token == Token.Else)
                    {
                        break;
                    }
                    ifStatement.ElseStatements.Add(this.GetStatementFromTokens(tokenEnumerator));
                }
            }
            if (flag)
            {
                tokenEnumerator.MoveNext();
                this.ExpectEndOfLine(tokenEnumerator);
            }
            else
            {
                this.AddError(ResourceHelper.GetString("EndIfExpected"));
            }
            return ifStatement;
        }
        private ElseIfStatement ConstructElseIfStatement(ref TokenEnumerator tokenEnumerator)
        {
            ElseIfStatement elseIfStatement = new ElseIfStatement
            {
                StartToken = tokenEnumerator.Current,
                ElseIfToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatLogicalExpression(tokenEnumerator, out elseIfStatement.Condition) && this.EatToken(tokenEnumerator, Token.Then, out elseIfStatement.ThenToken))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            for (tokenEnumerator = this.ReadNextLine(); tokenEnumerator != null; tokenEnumerator = this.ReadNextLine())
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.EndIf)
                {
                    break;
                }
                TokenInfo current2 = tokenEnumerator.Current;
                if (current2.Token == Token.Else)
                {
                    break;
                }
                TokenInfo current3 = tokenEnumerator.Current;
                if (current3.Token == Token.ElseIf)
                {
                    break;
                }
                TokenInfo current4 = tokenEnumerator.Current;
                if (current4.Token == Token.Sub)
                {
                    break;
                }
                TokenInfo current5 = tokenEnumerator.Current;
                if (current5.Token == Token.EndSub)
                {
                    break;
                }
                elseIfStatement.ThenStatements.Add(this.GetStatementFromTokens(tokenEnumerator));
            }
            return elseIfStatement;
        }
        private SubroutineStatement ConstructSubStatement(TokenEnumerator tokenEnumerator)
        {
            SubroutineStatement subroutineStatement = new SubroutineStatement
            {
                StartToken = tokenEnumerator.Current,
                SubToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            this.EatSimpleIdentifier(tokenEnumerator, out subroutineStatement.SubroutineName);
            this.ExpectEndOfLine(tokenEnumerator);
            tokenEnumerator = this.ReadNextLine();
            bool flag = false;
            while (tokenEnumerator != null)
            {
                TokenInfo current = tokenEnumerator.Current;
                if (current.Token == Token.EndSub)
                {
                    subroutineStatement.EndSubToken = tokenEnumerator.Current;
                    flag = true;
                    break;
                }
                TokenInfo current2 = tokenEnumerator.Current;
                if (current2.Token == Token.Sub)
                {
                    this.RewindLine();
                    break;
                }
                subroutineStatement.SubroutineBody.Add(this.GetStatementFromTokens(tokenEnumerator));
                tokenEnumerator = this.ReadNextLine();
            }
            if (flag)
            {
                tokenEnumerator.MoveNext();
                this.ExpectEndOfLine(tokenEnumerator);
            }
            else
            {
                this.AddError(ResourceHelper.GetString("EndSubExpected"));
            }
            return subroutineStatement;
        }
        private GotoStatement ConstructGotoStatement(TokenEnumerator tokenEnumerator)
        {
            GotoStatement gotoStatement = new GotoStatement
            {
                StartToken = tokenEnumerator.Current,
                GotoToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            this.EatSimpleIdentifier(tokenEnumerator, out gotoStatement.Label);
            this.ExpectEndOfLine(tokenEnumerator);
            return gotoStatement;
        }
        private LabelStatement ConstructLabelStatement(TokenEnumerator tokenEnumerator)
        {
            LabelStatement labelStatement = new LabelStatement
            {
                StartToken = tokenEnumerator.Current,
                LabelToken = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatToken(tokenEnumerator, Token.Colon, out labelStatement.ColonToken))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            return labelStatement;
        }
        private Statement ConstructIdentifierStatement(TokenEnumerator tokenEnumerator)
        {
            TokenInfo current = tokenEnumerator.Current;
            TokenInfo tokenInfo = tokenEnumerator.PeekNext();
            if (tokenInfo.Equals(TokenInfo.Illegal))
            {
                this.AddError(tokenEnumerator.Current, ResourceHelper.GetString("UnrecognizedStatement"));
                Expression leftValue = this.BuildIdentifierTerm(tokenEnumerator);
                return new AssignmentStatement
                {
                    StartToken = current,
                    LeftValue = leftValue
                };
            }
            if (tokenInfo.Token == Token.Colon)
            {
                return this.ConstructLabelStatement(tokenEnumerator);
            }
            if (tokenInfo.Token == Token.LeftParens)
            {
                return this.ConstructSubroutineCallStatement(tokenEnumerator);
            }
            TokenInfo current2 = tokenEnumerator.Current;
            int arg_90_0 = current2.Column;
            Expression expression = this.BuildIdentifierTerm(tokenEnumerator);
            if (expression is MethodCallExpression)
            {
                this.ExpectEndOfLine(tokenEnumerator);
                return new MethodCallStatement
                {
                    StartToken = current,
                    MethodCallExpression = expression as MethodCallExpression
                };
            }
            AssignmentStatement assignmentStatement = new AssignmentStatement
            {
                StartToken = current,
                LeftValue = expression
            };
            if (this.EatOptionalToken(tokenEnumerator, Token.Equals, out assignmentStatement.EqualsToken))
            {
                assignmentStatement.RightValue = this.BuildArithmeticExpression(tokenEnumerator);
                if (assignmentStatement.RightValue == null)
                {
                    this.AddError(tokenEnumerator.Current, ResourceHelper.GetString("ExpressionExpected"));
                }
                this.ExpectEndOfLine(tokenEnumerator);
            }
            else
            {
                this.AddError(tokenEnumerator.Current, ResourceHelper.GetString("UnrecognizedStatement"));
            }
            return assignmentStatement;
        }
        private Statement ConstructSubroutineCallStatement(TokenEnumerator tokenEnumerator)
        {
            SubroutineCallStatement result = new SubroutineCallStatement
            {
                StartToken = tokenEnumerator.Current,
                SubroutineName = tokenEnumerator.Current
            };
            tokenEnumerator.MoveNext();
            if (this.EatToken(tokenEnumerator, Token.LeftParens) && this.EatToken(tokenEnumerator, Token.RightParens))
            {
                this.ExpectEndOfLine(tokenEnumerator);
            }
            return result;
        }
    }
}
